#include <all_gd.h>
#pragma hdrstop
#pragma package(smart_init)

#include "int.h"

#if 0
  #define  PROC( v )
  #define  Log( v )
#else
  #define  PROC( v )  INProc __proc v ;
  #define  Log( v )   INProc::Say v
#endif

//---------------------------------------------------------------------------
// OZIMapLoader
//---------------------------------------------------------------------------
OZIMapLoader::OZIMapLoader( PMVModule own ) : MVMapLoader( own ) {}

void OZIMapLoader::LogErrorPoint( const OZIMapPoint& p )
  {
     if ( p.isLatLon )
       RTLog( "%dx%d, %f(%c), %f(%c): %s", p.x, p.y, p.gX, p.WE, p.gY, p.SN, FIO_ERROR );
      else
       RTLog( "%dx%d, n:%d, e:%d %c: %s", p.x, p.y, p.n, p.e, p.hemisphere, FIO_ERROR );
}

bool OZIMapLoader::NormalizeLoad( void )
  {
     for( int n = 0; n < TmpPoints.Count(); n++ )
       if ( !AddMapPoint( *TmpPoints[n] ) )
         return false;
     TmpPoints.DeleteAll();

     if ( !MVMapLoader::NormalizeLoad() )
       return false;

 return true;
}

bool OZIMapLoader::AddMapPoint( const OZIMapPoint& _p )
  {  OZIMapPoint p( _p );
     GMapPoint mp;

     mp.x = p.x;
     mp.y = p.y;

     if ( p.isLatLon ) {
       if ( p.SN == 'S' ) p.gY = -p.gY;
       if ( p.WE == 'W' ) p.gX = -p.gX;
     }

     if ( CoordSys == Geodetic ) {
       if ( !p.isLatLon ) {
         SetError( LNG("Impossible to set NE coordinates for Geodetic coord system") );
         LogErrorPoint( _p );
         return false;
       }

       mp.g.x = p.gX;
       mp.g.y = p.gY;
     } else {
       if ( p.isLatLon ) {
         if ( !CVT_LatLon2Any( p.gX, p.gY, CoordSys, Datum, &Projection, p ) ||
              GD_IsError(CVT_GetState()) ) {
           SetError( LNG("Error during point conversion") );
           LogErrorPoint( _p );
           return false;
         }
       }
       mp.ne.n = p.n;
       mp.ne.e = p.e;
     }

     Log(( "MP: %d,%d - %" GC_FMT ",%" GC_FMT, mp.x, mp.y, mp.g.x, mp.g.y ));
     MapPoints.Add( mp );
 return true;    
}

#define OZI_MAP_HEADER "OziExplorer Map Data File Version"

enum stages {
  stageHeader,
  stagePoint,
  stageMF,
  stageTrack,
  stageMM,
  stageMMP,
  stageMML,
  stageOther
};

bool OZIMapLoader::Load( CONSTSTR fnm )
  {  char     str[ 200 ];
     int      n;
     bool     done = false;
     stages   stage;

     Clear();
     MapFile = MakeStartLocalPath(fnm);
     Log(( "OZI map file: %s", MapFile.c_str() ));

     FILE *f = fopen( MapFile.c_str(), "rt" );
     if ( !f )
       return false;

     __try{
       for( stage = stageHeader, n = 1; !done && !feof(f) && !ferror(f) && fgets( str, sizeof(str), f ) != NULL; n++ ) {
         char *m = STrim(str),
              *e;
         if ( !m[0] ) continue;

         switch( stage ) {
           case stageHeader: //Header
                               if ( n == 1 ) {
                                 if ( StrNCmp( m, OZI_MAP_HEADER, strLen(OZI_MAP_HEADER) ) != 0 ) {
                                   FIO_SETERRORN( ERROR_NOT_SUPPORTED );
                                   return false;
                                 }
                               } else
                             //Caption
                               if ( n == 2 ) {
                                 Caption = m;
                                 Log(( "Caption: %s", Caption.c_str() ));
                               } else
                             //Image
                               if ( n == 3 ) {
                                 ImageFile = m;
                                 Log(( "Image: %s", ImageFile.c_str() ));
                               } else
                             //Map code (ignore)
                               if ( n == 4 ) {
                                 if ( strstr( m, "Map Code" ) == NULL &&
                                      strstr( m, "TIFF scale factor" ) == NULL ) {
                                   SetError( "Unknown map code: %s", m );
                                   return false;
                                 }
                               } else
                             //Datum settings
                               if ( n == 5 ) {
                                 m = SCol(m,1);
                                 Datum = OziDatum2Datum( m );
                                 if ( Datum == -1 ) {
                                   SetError( LNG("Datum \"%s\" is not supported"), m );
                                   return false;
                                 }
                                 Log(( "Map datum: %d (%s)", Datum, GD_DatumName(Datum) ));
                               } else
                             //"Reserved 1"
                               if ( n == 6 ) {
                               } else
                             //"Reserved 2"
                               if ( n == 7 ) {
                               } else
                             //"Magnetic Variation,,,E"
                               if ( n == 8 ) {
                               } else
                             //Map projection
                               if ( n == 9 ) {
                                 /* Map Projection,Transverse Mercator,PolyCal,No,AutoCalOnly,No,BSBUseWPX,No
                                    Map Projection,Latitude/Longitude,PolyCal,No,AutoCalOnly,No,BSBUseWPX,No
                                    Map Projection,Lambert Conformal Conic,PolyCal,No,AutoCalOnly,No,BSBUseWPX,Yes
                                 */
                                 m = SCol( m, 2 );
                                 CoordSys = OziProjection2CoordSys( m );
                                 if ( CoordSys == CoordSUnknown ) {
                                   SetError( LNG("Projection \"%s\" is not supported"), m );
                                   return false;
                                 }

                                 Log(( "Map coord sys: %d(%s)", CoordSys, GD_CoordName(CoordSys) ));

                                 stage = stagePoint;
                                 n     = 0;
                               } else {
                                 SetError( "Unexpected header line: %s", m );
                                 return false;
                               }
                          break;

           case stagePoint: //Projection
                             if ( StrNCmp( m, "Projection Setup", 16 ) == 0 ) {
                               /* Projection Setup,     0.000000000,    39.000000000,     1.000000000,       500000.00,            0.00,,,,,
                                  Projection Setup, 0.000000000, 152.000000000, 1.000000000, 2500000.00, 100000.00, -24.666667000, -27.333333000,,,
                               */
                               Projection.origin_latitude  = G2Rad( atof( SCol( m, 2 ) ) );
                               Projection.central_meridian = G2Rad( atof( SCol( m, 3 ) ) );
                               Projection.scale            = atof( SCol( m, 4 ) );
                               Projection.false_easting    = atof( SCol( m, 5 ) );
                               Projection.false_northing   = atof( SCol( m, 6 ) );
                               Projection.std_parallel_1   = G2Rad( atof( SCol( m, 7 ) ) );
                               Projection.std_parallel_2   = G2Rad( atof( SCol( m, 8 ) ) );
                               Projection.height           = atof( SCol( m, 9 ) );

                               if ( Projection.scale == 0 )
                                 Projection.scale = 1;

                               stage = stageMF;
                               n     = 0;
                             } else {
                               //Points
                               if ( StrNCmp( m, "Point", 5 ) != 0 ||
                                    !isdigit( m[5] ) ) {
                                 SetError( "Expected point description but found: [%s]", m );
                                 return false;
                               }
                               /* Lat\Lon
                                  Map Projection,Transverse Mercator,PolyCal,No,AutoCalOnly,No,BSBUseWPX,No
                                  Point01,xy,  545,  586,in, deg,  58, 40.0000,N,  57, 30.0000,E, grid,   ,           ,           ,N
                                  Point02,xy, 8303,  579,in, deg,  58, 40.0000,N,  66,  0.0000,E, grid,   ,           ,           ,N
                                  Point03,xy, 8075, 4688,in, deg,  56, 20.0000,N,  65, 30.0000,E, grid,   ,           ,           ,N
                                  Point04,xy,  295, 4668,in, deg,  56, 20.0000,N,  57, 30.0000,E, grid,   ,           ,           ,N
                                  Point05,xy, 4670, 4789,in, deg,  56, 20.0000,N,  62,  0.0000,E, grid,   ,           ,           ,N
                                  Point06,xy, 4648,  117,in, deg,  59,  0.0000,N,  62,  0.0000,E, grid,   ,           ,           ,N
                               */
                               /* UTM
                                  Map Projection,Transverse Mercator,PolyCal,No,AutoCalOnly,No,BSBUseWPX,No
                                  Point01,xy,  172,   98,in, deg,    ,        ,N,    ,        ,E, grid,   ,     324000,    6408000,N
                                  Point02,xy, 1948,  123,in, deg,    ,        ,N,    ,        ,E, grid,   ,     384000,    6404000,N
                                  Point03,xy, 1910, 1664,in, deg,    ,        ,N,    ,        ,E, grid,   ,     380000,    6352000,N
                                  Point04,xy,  137, 1637,in, deg,    ,        ,N,    ,        ,E, grid,   ,     320000,    6356000,N
                               */
                               /* None
                                  Point05,xy,     ,     ,ex, deg,    ,        ,N,    ,        ,E, grid,   ,           ,           ,N
                               */
                               OZIMapPoint pt;
                               memset( &pt, 0, sizeof(pt) );

                               do{
                                 e = SCol( m, 3 );
                                 if ( !e[0] ) break;
                                 pt.x = AtoI( e );

                                 e = SCol( m, 4 );
                                 if ( !e[0] ) break;
                                 pt.y = AtoI( e );

                                 e = SCol( m, 7 );
                                 if ( e[0] ) {
                                   pt.isLatLon = true;

                                   pt.gY  = atof( e );
                                   pt.gY  = FromDM( pt.gY, atof( SCol( m, 8 ) ) );
                                   pt.SN  = SCol( m, 9 )[0];
                                   if ( strchr( "SN", pt.SN ) == NULL ) {
                                     RTLog( "Invalid SN symbol: %c", pt.SN );
                                     break;
                                   }

                                   pt.gX = atof( SCol( m, 10 ) );
                                   pt.gX = FromDM( pt.gX, atof( SCol( m, 11 ) ) );
                                   pt.WE = SCol( m, 12 )[0];
                                   if ( strchr( "WE", pt.WE ) == NULL ) {
                                     RTLog( "Invalid WE symbol: %c", pt.WE );
                                     break;
                                   }
                                 } else {
                                   pt.isLatLon = false;
                                   pt.e  = AtoI( SCol( m, 15 ) );
                                   pt.n  = AtoI( SCol( m, 16 ) );
                                   pt.hemisphere = SCol( m, 17 )[0];
                                 }

                                 Log(( "Pt: %d,%d, LL: %f,%f (%c,%c), NE: %d,%d (%c)",
                                       pt.x, pt.y, pt.gX, pt.gY, pt.SN, pt.WE, pt.e, pt.n, pt.hemisphere ));
                                 TmpPoints.Add( pt );
                               }while( 0 );
                             }
                          break;

           case     stageMF: if ( StrNCmp( m, "Track File ", 11 ) == 0 ) {
                               stage = stageTrack;
                               n = 0;
                             }
                          break;

           case  stageTrack: if ( StrNCmp( m, "Moving Map Parameters", 21 ) == 0 ) {
                               stage = stageMM;
                               n = 0;
                             }
                          break;

           case     stageMM: if ( StrNCmp( m, "MMPXY", 5 ) == 0 ) {
                               stage = stageMMP;
                               n = 1;
                             } else
                               break;

           case    stageMMP: if ( StrNCmp( m, "MMPLL", 5 ) == 0 ) {
                               stage = stageMML;
                               n = 1;
                             } else {
                               MVBoundPoint bp;
                               bp.x = AtoI( SCol( m, 3 ) );
                               bp.y = AtoI( SCol( m, 4 ) );
                               bp.gX = 0;
                               bp.gY = 0;

                               Log(( "BP[%d]: %d,%d", Bounds.Count()+1, bp.x, bp.y ));
                               Bounds.Add( bp );
                               break;
                             }

           case    stageMML: if ( StrNCmp( m, "MMPLL", 5 ) != 0 )
                               done = true;
                              else {
                               int           num = AtoI( SCol( m, 2 ) );
                               PMVBoundPoint bp = Bounds.Item( num-1 );
                               if ( !bp ) {
                                 RTLog( "Bound point %d not found!", num );
                                 break;
                               }

                               bp->gX = atof( SCol( m, 3 ) );
                               bp->gY = atof( SCol( m, 4 ) );
                               Log(( "BP[%d]: %f,%f", num, bp->gX, bp->gY ));
                             }
                          break;
         }/*stages*/
       }/*lines*/
     }__finally{
       HSaveError _err;
       fclose( f );
     }

 return NormalizeLoad();
}
